package com.mrx.xfriendship.service.impl;

import com.mrx.commons.config.MinioProperties;
import com.mrx.commons.util.asserts.Asserts;
import com.mrx.xfriendship.service.IMinioService;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.http.Method;
import lombok.SneakyThrows;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Service
@DubboService
public class MinioServiceImpl implements IMinioService {

    private static final Logger logger = LoggerFactory.getLogger(MinioServiceImpl.class);

    @Resource
    private MinioProperties prop;

    @Resource
    private MinioClient minioClient;

    /**
     * 文件上传
     *
     * @param file 文件
     * @return Boolean
     */
    @Override
    @SneakyThrows
    public String upload(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        logger.debug("准备上传文件到 bucket: {}", originalFilename);
        Asserts.FILE_NAME_ERROR.checkTrue(StringUtils.hasText(originalFilename));
        try (InputStream fileInputStream = file.getInputStream()) {
            // TODO: 2023-05-10 上午 10:30:21 目前的实现不是很优雅
            InputStream inputStream = new ByteArrayInputStream(fileInputStream.readAllBytes());
            @SuppressWarnings("DataFlowIssue")
            String fileName = LocalDateTime.now().format(DateTimeFormatter.BASIC_ISO_DATE)
                    + "/"
                    + DigestUtils.md5DigestAsHex(inputStream)
                    + originalFilename.substring(originalFilename.lastIndexOf("."));
            logger.debug("bucket 文件名: {}", fileName);
            logger.debug("开始上传文件到 bucket");
            // 重置流, 上边的 MD5 已经读过一次了, 如果不重置将会报错
            inputStream.reset();
            PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(prop.getBucketName()).object(fileName)
                    .stream(inputStream, file.getSize(), -1).contentType(file.getContentType()).build();
            // 文件名称相同会覆盖
            minioClient.putObject(objectArgs);
            return fileName;
        }
    }

    @Override
    @SneakyThrows
    public String preview(String fileName) {
        fileName = fileName == null ? "NOT_EXISTS_FILE" : fileName;
        return minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .bucket(prop.getBucketName())
                        .object(fileName)
                        .method(Method.GET)
                        .build()
        );
    }

    /**
     * 删除
     */
    @Override
    @SneakyThrows
    public void remove(String fileName) {
        minioClient.removeObject(RemoveObjectArgs.builder().bucket(prop.getBucketName()).object(fileName).build());
    }

    @Override
    @SneakyThrows
    public Integer bucketNumber() {
        return minioClient.listBuckets().size();
    }

}
